package com.sugon.modules.kpi.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.sugon.entity.DeviceInfoEntity;
import com.sugon.modules.analyse.consts.KpiTarget;
import com.sugon.modules.analyse.model.chart.KpiTargetBarEchartOptionDataVO;
import com.sugon.modules.analyse.model.vo.DeviceKpiStatParamVO;
import com.sugon.modules.kpi.consts.DeviceOrganizationLevel;
import com.sugon.modules.kpi.model.StopLineStatVO;
import com.sugon.modules.kpi.service.IKpiTargetComputor;
import com.sugon.modules.report.service.IDayProductCountManager;
import com.sugon.modules.report.service.IShiftProjectManager;
import com.sugon.modules.report.service.IStopLineOrDeviceManager;
import com.sugon.modules.utils.MapUtil;
import com.sugon.service.DeviceInfoService;
import com.sugon.service.SysConfigService;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ： YuXD
 * @description： OEE KPI计算器实现类
 * @date ： 2020-11-15 下午 3:27
 * @version: 1.0
 */
@Service
public class OEEKPIComputorImpl implements IKpiTargetComputor {

    @Autowired
    private IShiftProjectManager shiftProjectManager;
    @Autowired
    private IStopLineOrDeviceManager stopLineOrDeviceManager;
    @Autowired
    private IDayProductCountManager dayProductCountManager;
    @Autowired
    private SysConfigService configService;
    @Autowired
    private DeviceInfoService deviceInfoService;

    @Override
    public KpiTargetBarEchartOptionDataVO compute(DeviceKpiStatParamVO kpiStatParam) {
        KpiTargetBarEchartOptionDataVO kpiTargetOption = new KpiTargetBarEchartOptionDataVO();
        // 获取月度良品率统计数据
        Map<Integer, Double> monthlyLplStatData = monthlyLplStat(kpiStatParam);
        // 获取月度时间开动率统计数据
        Map<Integer, Double> monthlySjkdlStatData = monthlySjkdlStat(kpiStatParam);
        // 获取月度性能开动率统计数据
        Map<Integer, Double> monthlyXnkdlStatData = monthlyXnkdlStat(kpiStatParam);
        // 组装数据
        for (int i = 1; i <= 12; i++) {
            Double monthlyLpl = MapUtil.getDouble(monthlyLplStatData, i, 0.0);
            Double monthlySjkdl = MapUtil.getDouble(monthlySjkdlStatData, i, 0.0);
            Double monthlyXnkdl = MapUtil.getDouble(monthlyXnkdlStatData, i, 0.0);
            kpiTargetOption.add(NumberUtil.round(monthlyLpl * monthlySjkdl * monthlyXnkdl, 3).doubleValue());
        }
        return kpiTargetOption;
    }

    /**
     * 月度良品率统计
     *
     * @param kpiStatParam
     * @return
     */
    private Map<Integer, Double> monthlyLplStat(DeviceKpiStatParamVO kpiStatParam) {
        Map<Integer, Double> monthlySjkdlStat = new HashMap<>(12);
        // 获取月度产线/设备实际产量总数
        Map<Integer, Integer> monthlyProductCountStat = dayProductCountManager.getMonthlyProductCountStat(kpiStatParam);
        // 获取月度产线/设备总次品数量
        Map<Integer, Integer> monthlyBadProductCountStat = dayProductCountManager.getMonthlyBadProductCountStat(kpiStatParam);
        for (int i = 1; i <= 12; i++) {
            // 只处理月度产线或设备实际产量总数大于0 的场景
            Integer monthlyProductCount = MapUtil.getInt(monthlyProductCountStat, i, 0);
            if (monthlyProductCount > 0) {
                // 不良品数
                Integer monthlyBadProductCount = MapUtil.getInt(monthlyBadProductCountStat, i, 0);
                monthlySjkdlStat.put(i, NumberUtil.div((monthlyProductCount - monthlyBadProductCount), monthlyProductCount.floatValue(), 2, RoundingMode.HALF_UP));
            }
        }
        return monthlySjkdlStat;
    }

    /**
     * 月度时间开动率统计
     *
     * @param kpiStatParam
     * @return
     */
    private Map<Integer, Double> monthlySjkdlStat(DeviceKpiStatParamVO kpiStatParam) {
        Map<Integer, Double> monthlySjkdlStat = new HashMap<>(12);
        // 获取月度负荷时间统计信息
        Map<Integer, Double> monthlyFuheHourTotalStat = shiftProjectManager.doYearlyLineShiftStat(kpiStatParam);
        // 获取设备停机或产线停线累计时长统计
        Map<Integer, StopLineStatVO> yearlyStopHourTotalStat = stopLineOrDeviceManager.doYearlyStopLineOrDeviceHourTotalStat(kpiStatParam);
        for (int i = 1; i <= 12; i++) {
            // 获取产线/设备负荷时间
            Double monthlyFuheHourTotal = MapUtil.getDouble(monthlyFuheHourTotalStat, i, 0.0);
            if (monthlyFuheHourTotal > 0) {
                StopLineStatVO monthlyStopHourTotal = yearlyStopHourTotalStat.get(i);
                Double stopMinuteTotal = (monthlyStopHourTotal != null) ? monthlyStopHourTotal.getMinuteTotal() : 0.0;
                monthlySjkdlStat.put(i, NumberUtil.div((monthlyFuheHourTotal - stopMinuteTotal), monthlyFuheHourTotal.doubleValue(), 2, RoundingMode.HALF_UP));
            }
        }
        return monthlySjkdlStat;
    }

    /**
     * 月度性能开动率统计
     *
     * @param kpiStatParam
     * @return
     */
    private Map<Integer, Double> monthlyXnkdlStat(DeviceKpiStatParamVO kpiStatParam) {
        // 获取当前产线/设备的计划节拍时间
        Double linePlanBeatTime = getPlanBeatTime(kpiStatParam);
        // 获取月度产线/设备实际产量总数
        Map<Integer, Integer> monthlyProductCountStat = dayProductCountManager.getMonthlyProductCountStat(kpiStatParam);
        // 获取产线/设备的停线或停机时间统计
        Map<Integer, StopLineStatVO> mttrStatMap = stopLineOrDeviceManager.doYearlyStopLineOrDeviceHourTotalStat(kpiStatParam);

        // 获取产线/设备的排班时长统计数据
        Map<Integer, Double> shiftHourTotalStatMap = shiftProjectManager.doYearlyLineShiftStat(kpiStatParam);
        // 创建结果MAP
        Map<Integer, Double> result = new HashMap<>(12);
        for (int i = 1; i <= 12; i++) {
            // 获取月度产量数目
            Integer monthlyProductCount = MapUtil.getInt(monthlyProductCountStat, i, 0);
            // 获取排班时间
            Double shiftAccuStat = MapUtil.getDouble(shiftHourTotalStatMap, i, 0);
            if (monthlyProductCount != 0 && shiftAccuStat != 0) {
                // 获取停线时间
                StopLineStatVO stopLineStat = mttrStatMap.get(i);
                Double stopLineMinuteTotal = (stopLineStat == null ? 0.0 : stopLineStat.getMinuteTotal());
                // 计算实际工作时长
                Double actualWorkHourTotal = shiftAccuStat - stopLineMinuteTotal;
                Assert.isTrue(actualWorkHourTotal >= 0, "停线或故障时长不可能大于排班时长");
                if (actualWorkHourTotal > 0) {
                    // 计算公式：(产线计划节拍时间 X 实际产量) /产线运转时间
                    result.put(i, NumberUtil.div(NumberUtil.mul(linePlanBeatTime, monthlyProductCount), actualWorkHourTotal, 2, RoundingMode.HALF_UP).doubleValue());
                }
            }
        }
        return result;
    }

    /**
     * 获取产线/设备计划节拍时间
     *
     * @param kpiStatParam
     * @return
     */
    private Double getPlanBeatTime(DeviceKpiStatParamVO kpiStatParam) {
        // 声明计划节拍时间
        Double planBeanTime = 0.0;
        if (kpiStatParam.getLevel().equals(DeviceOrganizationLevel.LINE)) {
            planBeanTime = configService.getPlanBeatTime(kpiStatParam.getDeviceOrganizationCode());
        } else {
            DeviceInfoEntity device = deviceInfoService.queryObject(kpiStatParam.getDeviceOrganizationId());
            Assert.notNull(device, "设备不存在，设备编码：" + kpiStatParam.getDeviceOrganizationCode());
            planBeanTime = configService.getPlanBeatTime(device.getDevProductCode());
        }
        return planBeanTime;
    }

    @Override
    public KpiTarget getType() {
        return KpiTarget.OEE;
    }

}
